package cn.com.bluemoon.daps.sync.service.impl;

import cn.com.bluemoon.daps.common.exception.DapThrowException;
import cn.com.bluemoon.daps.sync.base.CompareResult;
import cn.com.bluemoon.daps.sync.base.SqlCompareResult;
import cn.hutool.core.util.StrUtil;
import com.alibaba.druid.DbType;
import com.alibaba.druid.sql.ast.SQLDataType;
import com.alibaba.druid.sql.ast.SQLName;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableItem;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableStatement;
import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableAlterColumn;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableChangeColumn;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableModifyColumn;
import com.google.common.collect.ImmutableSet;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

/**
 * // 2021-10-20
 * //模型管理-同步管理-同步详情-确认同步-更新状态
 * //【修改】后端-timestamp/datetime数据类型会根据实例参数explicit_defaults_for_timestamp不同而指定额外字段数据   查看截图，在同步管理中更新状态时，忽略是否为空、默认值的校验
 * //即，日期时间戳类型，在保证字段名相同、长度相同、注释相同，则允许更改状态
 *
 * @author Jarod.Kong
 */
@Component
@Slf4j
public class AlterTableTimestampModifySyncStatusHandler extends AlterTableFieldModifySyncStatusBaseHandler {
    private static final Set<String> DEFAULT_ENABLE_FORCE_DATA_TYPES = ImmutableSet.of("timestamp", "datetime");

    @Override
    public boolean matchAlterTableField(String tableName, CompareResult<SqlCompareResult> fieldCompare, String fieldAlterSql) throws DapThrowException {
        SQLAlterTableStatement statement = parseAlterStats(fieldAlterSql, DbType.mysql);
        if (statement != null) {
            // 表中sqls都符合整型类型，长度为空的情况可以强制修改
            List<SQLAlterTableItem> statementItems = statement.getItems();
            if (statementItems.isEmpty()) {
                log.info("获取修改表语句的item项为空，结束");
                return false;
            }
            boolean allMatchAlterTableChangeCol = statementItems.stream()
                    .allMatch(m -> m instanceof MySqlAlterTableChangeColumn ||
                            m instanceof MySqlAlterTableAlterColumn ||
                            m instanceof MySqlAlterTableModifyColumn);
            if (!allMatchAlterTableChangeCol) {
                log.info("当前修改表不都是修改字段语句，结束");
                return false;
            }
            final Map<String, List<Object>> desc = fieldCompare.getDesc();
            List<MySqlAlterTableChangeColumn> changeColumns = statementItems.stream()
                    .filter(m -> m instanceof MySqlAlterTableChangeColumn)
                    .map(m -> (MySqlAlterTableChangeColumn) m)
                    .filter(m -> {
                        SQLName columnName = m.getColumnName();
                        SQLColumnDefinition newColDef = m.getNewColumnDefinition();
                        SQLDataType dataType = newColDef.getDataType();
                        // 对比字段类型都一致或者不是datetime和timestamp其一
                        List<Object> dataTypeValues = desc.getOrDefault("dataType", new ArrayList<>(2));
                        boolean dataTypeDiff = !desc.containsKey("dataType") || // 无差异
                                (DEFAULT_ENABLE_FORCE_DATA_TYPES.contains(getDataTypeLowerCase(dataTypeValues, 0)) &&
                                        DEFAULT_ENABLE_FORCE_DATA_TYPES.contains(getDataTypeLowerCase(dataTypeValues, 1))); // 有差异但是都是符合类型
                        if (DEFAULT_ENABLE_FORCE_DATA_TYPES.contains(dataType.getName().toLowerCase()) && dataTypeDiff) {
                            return StrUtil.equalsIgnoreCase(columnName.getSimpleName(), newColDef.getColumnName()) && // 字段名相等
                                    !desc.containsKey("length") && // 无差异
                                    !desc.containsKey("comment"); // 无差异
                        }
                        return false;
                    })
                    .collect(Collectors.toList());
            if (statementItems.size() == changeColumns.size()) {
                log.warn("修改字段符合强制更改规则，sql=>{}，允许修改表{}状态", fieldAlterSql, tableName);
                return true;
            } else {
                log.info("修改字段不符合强制更改规则，不可修改状态");
            }
        }
        return false;
    }

    private String getDataTypeLowerCase(List<Object> dataType, int i) {
        return Objects.toString(dataType.get(i), "").toLowerCase();
    }

}
